import http from '@ohos.net.http'
import promptAction from '@ohos.promptAction'
import router from '@ohos.router'
import { Auth } from './auth'
import { Logger } from './logger'

class Res<ResData = unknown> {
  code: number
  message: string
  data: ResData
}

const req = http.createHttp()

const BASE_URL = 'https://api-harmony-teach.itheima.net/hm/'

// 公共的请求方法
const request = <ResData = unknown>(url: string, method: http.RequestMethod = http.RequestMethod.GET, params: object = {
}) => {

  // 处理请求地址 以/开头 兼容问题
  if (url.startsWith('/')) {
    url = url.slice(1)
  }

  let fullUrl = BASE_URL + url

  // 默认请求配置
  const options: http.HttpRequestOptions = {
    method, // 请求方法
    readTimeout: 1000 * 30, // 超时时间，单位（ms）
    header: {
      // 指定请求数据类型为json格式，告诉后端，我给你的数据是json格式的，你就用json格式解析即可
      'Content-Type': 'application/json'
    }
  }

  // 由于，GET请求的参数需要拼接到地址后面，其他方式的请求 需要通过 extraData 来传递
  if (method === http.RequestMethod.GET) {
    // params ==> { name: 'zs', age: 18 } =要转成=> name=zs&age=18
    fullUrl += '?' + Object.entries(params).map(([k, v]) => `${k}=${v}`).join('&')
  } else {
    options.extraData = params
  }

  // 注入token
  const user = Auth.getUser()
  if (user.token) {
    // 登录了
    options.header['Authorization'] = 'Bearer ' + user.token
  }

  Logger.info(`Request → ${fullUrl} → ${method} → ${JSON.stringify(params)}`)

  // 真正的发出请求
  return req.request(fullUrl, options).then((res) => {

    Logger.info(`Response Success → ${fullUrl} → ${method} → ${JSON.stringify(params)}`, res.result.toString().slice(0, 250))

    // 请求成功了，但是业务不一定成功
    const response = JSON.parse(res.result as string) as Res<ResData>

    // 成功了
    if (response.code === 10000) {
      return response
    }

    // token失效，要去登录页
    if (response.code === 401) {
      // 当用户打开某个页面时，有可能一下发多个请求吧？  对，可能
      // 场景：当发送多次请求时，如果 token 失效了，每个的请求都会 跳一次 登录页
      // 而，router.pushUrl 方法 每跳一次 都会 增加一个页面栈记录
      router.pushUrl({
        url: 'pages/LoginPage'
      }, router.RouterMode.Single) // 如果是 router.RouterMode.Single 模式，则同样的页面 不会添加多个，只会存在一个
    }

    return Promise.reject(res)
  }, (err) => {
    Logger.error(`Response Error → ${fullUrl} → ${method} → ${JSON.stringify(params)}`, JSON.stringify(err).slice(0, 250))
    // 走到这里，说明是网络本身的问题：后台服务器挂了，网络有问题，等等。。。
    promptAction.showToast({ message: '系统繁忙，请稍后重试！' })
    return Promise.reject(err)
  }).finally(() => {
    // 释放请求资源
    req.destroy()
  })
}


export class Request {

  // 调用范例：const res = await Request.get<UserModel>('/userinfo')    res.data. 点出用户类型的属性提示
  static get<ResData = unknown>(url: string, params: object = {}) {
    return request<ResData>(url, http.RequestMethod.GET, params)
  }

  static post<ResData = unknown>(url: string, params: object = {}) {
    return request<ResData>(url, http.RequestMethod.POST, params)
  }

  static put<ResData = unknown>(url: string, params: object = {}) {
    return request<ResData>(url, http.RequestMethod.PUT, params)
  }

  static delete<ResData = unknown>(url: string, params: object = {}) {
    return request<ResData>(url, http.RequestMethod.DELETE, params)
  }
}